package com.zzyl.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.dto.NursingPlanDto;
import com.zzyl.entity.NursingPlan;
import com.zzyl.entity.NursingProject;
import com.zzyl.entity.NursingProjectPlan;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.NursingPlanMapper;
import com.zzyl.mapper.NursingProjectMapper;
import com.zzyl.mapper.NursingProjectPlanMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.service.NursingPlanService;
import com.zzyl.vo.NursingPlanVo;
import com.zzyl.vo.NursingProjectPlanVo;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author 12531
 * @description 针对表【nursing_plan(护理计划表)】的数据库操作Service实现
 * @createDate 2024-07-18 20:58:35
 */
@Service
public class NursingPlanServiceImpl implements NursingPlanService {

    private final NursingProjectMapper nursingProjectMapper;
    private final NursingPlanMapper nursingPlanMapper;
    private final NursingProjectPlanMapper nursingProjectPlanMapper;
    private final UserMapper userMapper;

    public NursingPlanServiceImpl(NursingProjectMapper nursingProjectMapper, NursingPlanMapper nursingPlanMapper, NursingProjectPlanMapper nursingProjectPlanMapper, UserMapper userMapper) {
        this.nursingProjectMapper = nursingProjectMapper;
        this.nursingPlanMapper = nursingPlanMapper;
        this.nursingProjectPlanMapper = nursingProjectPlanMapper;
        this.userMapper = userMapper;
    }


    // 查询所有护理计划
    @Override
    public List<NursingPlanVo> selectAll() {
        // 新建一个我们方法需要返回的集合
        List<NursingPlanVo> nursingPlanVoLists = new ArrayList<>();
        // 从数据库中查到的是entity集合(我们需要的是VO集合)
        List<NursingPlan> nursingPlanLists = nursingPlanMapper.selectAll();

        for (NursingPlan nursingPlan : nursingPlanLists) {
            NursingPlanVo nursingPlanVo = new NursingPlanVo();
            BeanUtils.copyProperties(nursingPlan, nursingPlanVo);
            nursingPlanVoLists.add(nursingPlanVo);
        }
        return nursingPlanVoLists;
    }

    // 分页条件查询护理计划
    @Override
    public PageResponse<NursingPlanVo> selectByPage(String name, Integer status, Integer pageNum, Integer pageSize) {

        Page<NursingPlan> NursingPlanPage = PageHelper.startPage(pageNum, pageSize).doSelectPage(
                () -> nursingPlanMapper.selectByPage(name, status)
        );

        NursingPlanPage.getResult().forEach(nursingPlan -> {
            // 给vo对象中的creator赋值
            try {
                String realName = userMapper.selectByPrimaryKey(nursingPlan.getCreateBy()).getRealName();
                nursingPlan.setCreator(realName);
            } catch (NullPointerException e) {
                nursingPlan.setCreator("Unknown Creator");
            }
        });

        /**
         *PageResponse.of()方法的作用
         *(1) 将分页查询的结果->Page对象 ->装为PageResponse
         *(2) 并将我们自定义的Page对象{@link PageResponse}中的Records(记录) 转换为指定类型封装为items
         *    records(copyToList(page.getResult(), clazz, convertHandler))
         */

        // 这行代码内部帮我们把 List<NursingPlan> 转换为 List<NursingPlanVo>
        return PageResponse.of(NursingPlanPage, NursingPlanVo.class);
    }


    // 根据id查询护理计划(包含项目)
    @Override
    public NursingPlanVo selectById(Long id) {
        NursingPlanVo nursingPlanVo = new NursingPlanVo();
        // 从nursingPlan表中查到的是一些基本数据
        NursingPlan nursingPlan = nursingPlanMapper.selectByPrimaryKey(id);
        BeanUtils.copyProperties(nursingPlan, nursingPlanVo);
        // 需要从nursingProjectPlan表中查询【该计划绑定的项目信息】
        // 我这里用VO接受的数据的返回！ 原来数据库返回的也可以是比他属性更多的对象！可以比他大！
        // 具体来说：<NursingProjectPlan>实体类中【没有ProjectName】，而我创建的VO中有
        // List<NursingProjectPlan> nppList = nursingProjectPlanMapper.selectByPlanId(id);

        List<NursingProjectPlanVo> nppList = nursingProjectPlanMapper.selectByPlanId(id);
        for (NursingProjectPlanVo npp : nppList) {
            NursingProject nursingProject = nursingProjectMapper.selectById(Long.valueOf(npp.getProjectId()));
            npp.setProjectName(nursingProject.getName());
        }
        nursingPlanVo.setProjectPlans(nppList);
        return nursingPlanVo;
    }

    // 新增护理计划(包含项目)
    @Override
    public int insert(NursingPlanDto nursingPlanDto) {
        // 1.校验参数
        // 护理计划名称(必填+唯一) 护理项目(必填) 执行频次(必填) 【完成一半】
        String planName = nursingPlanDto.getPlanName();
        if (ObjectUtils.isEmpty(planName)) {
            throw new BaseException(BasicEnum.NAME_IS_EMPTY);
        }
        // 2.业务处理
        // 护理计划名字必须唯一
        if (Objects.nonNull(nursingPlanMapper.selectByName(planName))) {
            throw new BaseException(BasicEnum.NAME_IS_EXIST);
        }
        // 护理项目不能为空，且其中的属性也不能为空
        if (Objects.isNull(nursingPlanDto.getProjectPlans())) {
            throw new BaseException(BasicEnum.PROJECT_IS_EMPTY);
        }
        // TODO 需要添加事务，因为包含两个数据库操作
        // 【操作1】创建entity对象，拷贝属性，填充数据，插入到数据库
        NursingPlan nursingPlan = new NursingPlan();
        BeanUtils.copyProperties(nursingPlanDto, nursingPlan);
        nursingPlan.setCreateTime(LocalDateTime.now());
        nursingPlan.setUpdateTime(LocalDateTime.now());
        nursingPlan.setCreateBy(1L);
        nursingPlan.setStatus(1);
        Long id1 = nursingPlan.getId();
        nursingPlanMapper.insert(nursingPlan);
        Long planId = nursingPlan.getId();
        
        // 【操作2】护理计划和护理项目绑定(操作NursingProjectPlan数据库)
        List<NursingProjectPlan> projectPlanList = nursingPlanDto.getProjectPlans();
        projectPlanList.forEach(projectPlan -> {
                    // 补充数据
                    projectPlan.setCreateBy(1L);
                    projectPlan.setCreateTime(LocalDateTime.now());
                    projectPlan.setUpdateTime(LocalDateTime.now());
                    // 前端在新增计划时，前端只传了一个id，就是绑定的项目的id
                    // 但是在执行项数据库插入时，计划id不能为空
                    // 在执行完第一个插入语句后，就可以获取到计划id了
                    projectPlan.setPlanId(Math.toIntExact(planId));
                    nursingProjectPlanMapper.insert(projectPlan);
                }
        );
        // TODO 只有在上述所有操作都成功后才返回1
        return 1;

    }
}




